#include <stdio.h>
#include <sys/types.h>
#include <pwd.h>
#include <unistd.h>
#include <dirent.h>
#include <sys/wait.h>
#include <errno.h>

#define DBGMSG(msg) printf("DBGMSG - %s\n", msg)

#define MAX 255
#define SIZE 1024

char path[MAX];
char *curpath;
char line[MAX];
char *save;
char *s;

int count;

static const char delim[] = " \t\n";
int pid, status;

int build_argv(char* cmdline, char*** buff);

main(int argc, char *argv[])
{
	char buf[MAX];
	char origin[MAX];
	DBGMSG(argv[0]);
	
	uid_t uid;
	struct passwd *pw;
	uid=getuid(); 
	// prompt에 출력할 user id 획득용
	pw=getpwuid(uid);
	// bin directory 설정
	setenv("BIN", "/root/simsh/bin/");

	while(1){
		// prompt 출력
		curpath = (char*) getenv("PWD");
		printf("[%s@%s]$ ", pw->pw_name, curpath);

		// 사용자 입력
		fgets(line, 255, stdin);

		// 후면 수행 할 것인지 검사
		int back = 0;
		int k = 0;
		int len = strlen(origin);
		for(k=0; k<len; k++)
		{
			if( ' ' != origin[strlen(origin) - k] || '&' != origin[strlen(origin) - k] )
				break;
			if( '&' == origin[strlen(origin) - k] )
			{
				back = 1;
				break;
			}
		}

		line[k] = '\0';
		strcpy(origin, line);

		s = strtok(line, delim);
		if( NULL == s )
		{
			free(origin);
			continue;
		}

		char* cmdname = (char*) malloc(strlen(s) + 1);
		strcpy(cmdname, s);
			
		if(cmdname){
			// built-in command (quit)
			if( !strcmp(cmdname, "quit") ) {
				exit(0);
			}
			// built-in command (chd)
			else if( !strcmp(cmdname, "chd") ) {
				int j;
				char** arr = NULL;
				int numtoks = buildargv(origin, &arr);
				chd(numtoks, arr);
				for(j=0; j<numtoks; j++)
				{
					free(arr[j]);
				}
				free(arr);
			}
			// built-in command (hlp)
			else if( !strcmp(cmdname, "hlp") ) {
				hlp();
			}
			else {
				// argument 목록 작성
				char** arr = NULL;
				int numtoks = buildargv(origin, &arr);

				// child process 생성
				pid_t pid = fork();
				if( 0 > pid ) {
					fprintf(stderr, "fork failed\n");
					exit(1);
				}
				if( 0 == pid ) {
					// child process
					// bin path 설정 후 exec로 process를 변환함
					char temp[1024];
					strcpy(temp, (char*) getenv("BIN"));
					strcpy(temp + strlen(temp), cmdname);
					DBGMSG(temp);
					
					if( -1 == execve(temp, arr, NULL) )
					{
						fprintf(stdout, "invalid command (%d)\n", errno);
						return 0;
					}
				}
				else {
					int j = 0;

					// parent process
					// 후면 수행이 아니면 child process가 종료될 때까지 대기
					if( !back )
						wait(NULL);

					// argument 목록을 삭제함
					for(j=0; j<numtoks; j++)
					{
						free(arr[j]);
					}
					free(arr);
				}

			}
		}// endof if(cmdname)
		free(cmdname);
	}// endof while
}

// chd 함수
void chd(int argc, char *argv[]){
	chdir(argv[1]);
	getcwd(curpath, MAX);
	setenv("PWD", curpath, 1); 
	//opendir(argv[1]);	
}

// hlp 함수
void hlp(){
	printf("chd <directory> : move to the target directory");
	printf("dir : show a file list in the directory");
	printf("   -l");
	printf("   -a");
	printf("slp <number>");
	printf("pause : pause");
	
}

// buildargv 함수
// argument 목록을 작성함
int buildargv(char* cmdline, char*** buffer)
{
	char* temp = (char*) malloc(strlen(cmdline) + 1);
	strcpy(temp, cmdline);

	s = strtok(temp, delim);
	// get num tokens
	int numtoks = 1;
	while( s = strtok(NULL, delim) ){
		numtoks += 1;
	}

	if( NULL == buffer )
	{
		free(temp);
		return numtoks;
	}

	strcpy(temp, cmdline);
	char** arr = (char**) malloc(sizeof(char**) * numtoks);
	s = strtok(temp, delim);
	int j = 0;
	for(j=0; j<numtoks; j++)
	{
		arr[j] = (char*) malloc(strlen(s) + 1);
		strcpy(arr[j], s);
		s = strtok(NULL, delim);
	}

	*buffer = arr;
	free(temp);
	return numtoks;
}

